package com.net.xpay.common.service.impl;

import com.google.common.base.Strings;
import com.net.xpay.common.domain.User;
import com.net.xpay.common.domain.UserProfile;
import com.net.xpay.common.domain.UserShard;
import com.net.xpay.common.domain.partner.Partner;
import com.net.xpay.common.domain.partner.PartnerCode;
import com.net.xpay.common.enums.config.CommonSysConfigKey;
import com.net.xpay.common.enums.user.*;
import com.net.xpay.common.helper.CommonSysConfigHelper;
import com.net.xpay.common.helper.RedisHelper;
import com.net.xpay.common.manager.UserManager;
import com.net.xpay.common.manager.UserProfileManager;
import com.net.xpay.common.manager.UserShardManager;
import com.net.xpay.common.model.PasswordModel;
import com.net.xpay.common.model.RegisterModel;
import com.net.xpay.common.model.UpdateUserServicePriceModel;
import com.net.xpay.common.validator.UserValidator;
import com.net.xpay.core.constant.CoreConstant;
import com.net.xpay.core.constant.PoseidonErrorCode;
import com.net.xpay.core.constant.RedisKey;
import com.net.xpay.core.domain.UserAccount;
import com.net.xpay.core.enums.OpenApiVersion;
import com.net.xpay.core.helper.ShardHelper;
import com.net.xpay.core.manager.PayTransBatchManager;
import com.net.xpay.core.manager.UserAccountManager;
import com.net.xpay.core.model.UpdatePartnerModel;
import com.net.xpay.core.model.UserTransLimitModel;
import com.net.common.exception.BusinessException;
import com.net.common.util.LocalDateUtil;
import com.net.common.util.SerializationUtil;
import com.net.xpay.common.enums.user.*;
import com.net.xpay.common.manager.partner.PartnerCodeManager;
import com.net.xpay.common.manager.partner.PartnerManager;
import com.net.xpay.common.service.UserService;
import com.net.shard.ShardContextHolder;
import com.net.shard.ShardUtil;
import lombok.extern.slf4j.Slf4j;
import org.mindrot.jbcrypt.BCrypt;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;

/**
 * @author on 02/02/2018.
 * 注意 类名上不要加事务 注册的时候还没有分库信息
 */
@Service
@Slf4j
public class UserServiceImpl implements UserService {
    @Autowired
    private UserManager userManager;
    @Autowired
    private UserAccountManager userAccountManager;
    @Autowired
    private UserValidator userValidator;
    @Autowired
    private UserShardManager userShardManager;
    @Autowired
    private ShardHelper shardHelper;
    @Autowired
    private UserProfileManager userProfileManager;
    @Autowired
    private PartnerCodeManager partnerCodeManager;
    @Autowired
    private PayTransBatchManager payTransBatchManager;
    @Autowired
    private CommonSysConfigHelper commonSysConfigHelper;
    @Autowired
    private PartnerManager partnerManager;
    @Autowired
    private RedisHelper redisHelper;


    @Override
    public User doRegister(RegisterModel registerModel) {

        userValidator.validateRegisterInfo(registerModel, false);  //验证

        //确认手机号未被注册
        if (userManager.findByMobile(registerModel.getMobile()) != null) {
            throw new BusinessException(PoseidonErrorCode.MOBILE_DUPLICATED, "手机号已经被注册,你可以使用找回密码功能");
        }

        return registerInternal(registerModel);
    }

    @Override
    public User autoRegister(RegisterModel registerModel) {
        userValidator.validateRegisterInfo(registerModel, true);  //验证

        return registerInternal(registerModel);
    }

    @Override
    public User resetPassword(PasswordModel passwordModel) {
        userValidator.validatePassword(passwordModel, CheckCodeType.RESET_PASSWORD);  //验证

        User user = userManager.findByMobile(passwordModel.getMobile());
        if (user == null) {
            throw new BusinessException(PoseidonErrorCode.MOBILE_NOT_FOUND, "手机号不存在,请确认账户是否正确");
        }

        setUserPassword(user, passwordModel.getPassword());
        userManager.updateByPrimaryKeyWithVersion(user);
        return user;
    }

    @Override
    public User modifyPassword(User user, PasswordModel passwordModel) {
        passwordModel.setMobile(user.getMobile());
        userValidator.validatePassword(passwordModel, CheckCodeType.MODIFY_PASSWORD);

        setUserPassword(user, passwordModel.getPassword());
        userManager.updateByPrimaryKeyWithVersion(user);
        return user;
    }

    @Override
    public User modifyPayPassword(User user, PasswordModel passwordModel) {
        passwordModel.setMobile(user.getMobile());
        userValidator.validatePassword(passwordModel, CheckCodeType.MODIFY_PAY_PASSWORD);

        setPayPassword(user, passwordModel.getPassword());
        userManager.updateByPrimaryKeyWithVersion(user);
        //密码输入正确，删除计数
        redisHelper.remove(RedisKey.MCH_PAY_PASSWORD_ERR_CNT + ":" + user.getId());
        return user;
    }

    @Override
    public User registerInternal(RegisterModel registerModel) {
        if (Strings.isNullOrEmpty(registerModel.getName())) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "商户名不能为空");
        }
        registerModel.setName(registerModel.getName().trim());
        User selected = userManager.findByName(registerModel.getName());
        if (selected != null) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "同名商户已被注册");
        }
        try {
            User user = createUser(registerModel);
            userManager.save(user);
            //创建用户配置信息
            UserProfile userProfile = createUserProfile(user.getId());
            if (Boolean.FALSE.equals(registerModel.getOpenMerchantPlatform())) {
                userProfile.setOpenMerchantPlatform(false);
                userProfileManager.update(userProfile);
            }
            //初始化用户路由
            UserShard userShard = registerUserShard(user);

            //初始化账户
            ShardUtil.setShardContext(userShard.getShardId());
            UserAccount account = UserAccount.getInstance(user);
            account.setTransBatchLeft(0L);
            userAccountManager.save(account);
            return user;
        } finally {
            ShardContextHolder.removeShardContext();
        }
    }

    @Override
    public UserProfile createUserProfile(Long userId) {
        UserProfile userProfile = UserProfile.getInstance();
        userProfile.setId(userId);
        userProfile.setOpenCharge(true);
        userProfile.setApiVersion(OpenApiVersion.V2);
        userProfile.setOpenSafePay(true);
        userProfile.setOpenMerchantPlatform(true);
        userProfile.setNeedSafePayAuth(true);
        userProfile.setOpenAutoPay(false);
        userProfile.setOpenSafePayOfflineCharge(true);
        userProfile.setOpenCollectionSafePay(false);
        userProfile.setOpenChargeNotify(false);
        userProfile.setOpenInvoice(false);
        userProfile.setOpenSafePayBank(false);
        userProfile.setOpenSafePayNewSignMethod(false);
        userProfile.setLimitSafePayWebPageTrans(false);

        try {
            Long openSafePayNewSignMethod = commonSysConfigHelper.getLong(CommonSysConfigKey.OPEN_SAFE_PAY_NEW_SIGN_METHOD);
            if (openSafePayNewSignMethod != null && openSafePayNewSignMethod == 1) {
                userProfile.setOpenSafePayNewSignMethod(true);
            }
        } catch (Exception e) {
            log.warn("openSafePayNewSignMethod,userId=" + userId, e);
        }

        userProfile.setStrictLogin(false);
        userProfile.setUseGoogleAuth(false);
        userProfile.setBatchEnsure(false);
        userProfile.setEnsureBatchAmount(new BigDecimal(0));
        userProfileManager.save(userProfile);
        return userProfile;
    }

    @Override
    public UserTransLimitModel getTransferLimit(User user, Long alipayUserId) {
        // 获取当前用户的userId和支付宝主账号id
        Long userId = user.getId();
        // 用户可能还没有绑定支付宝号码 所以如果未空的话 返回额度都为0
        if (alipayUserId == null) {
            return new UserTransLimitModel(new BigDecimal(0), new BigDecimal(0));
        }
        // 首先获取当前的时间
        LocalDateTime day = LocalDateTime.now();
        // 根据当前时间获取改天的起始时间和结束时间
        LocalDateTime currentDayStartTime = LocalDateUtil.getDayStart(day);
        LocalDateTime currentDayEndTime = LocalDateUtil.getDayEnd(day);
        // 根据当前时间获取该月的起始时间和结束时间
        LocalDateTime currentMonthStartTime = LocalDateUtil.getMonthStartDay(day);
        LocalDateTime currentMonthEndTime = LocalDateUtil.getMonthEndDay(day);
        // 进行查询
        BigDecimal currentDayLimit = payTransBatchManager.getTransferLimit(currentDayStartTime, currentDayEndTime, userId, alipayUserId);
        BigDecimal currentMonthLimit = payTransBatchManager.getTransferLimit(currentMonthStartTime, currentMonthEndTime, userId, alipayUserId);

        return new UserTransLimitModel(currentDayLimit, currentMonthLimit);
    }

    @Override
    public void updatePartner(UpdatePartnerModel model) {
        User user = userManager.getById(model.getId());
        user.setPartnerId(model.getPartnerId());
        Partner partner = partnerManager.getById(model.getPartnerId());
        user.setFatherPartnerId(partner.getFatherPartnerId());

        List<PartnerCode> partnerCodes = partnerCodeManager.listByPartnerId(model.getPartnerId());
        for (PartnerCode partnerCode : partnerCodes) {
            if (UserTag.PLATFORM == partnerCode.getUserTag()) {
                user.setPma(partnerCode.getPma());
                user.setMode(partnerCode.getMode());
                user.setCommissionMode(partnerCode.getCommissionMode());
                user.setBenefitRatio(partnerCode.getBenefitRatio());
                user.setFatherBenefitRatio(partnerCode.getFatherBenefitRatio());
                user.setCostServiceRatio(partnerCode.getCostServiceRatio());
                user.setBankCostServiceRatio(partnerCode.getSafePayBankCostServiceRatio());
                user.setPartnerBenefit(partnerCode.getBenefit());
                user.setFatherPartnerId(partnerCode.getFatherPartnerId());
                user.setFatherPartnerBenefit(partnerCode.getFatherBenefit());
                user.setFatherCommissionMode(partnerCode.getFatherCommissionMode());
                user.setFatherServiceRatio(partnerCode.getFatherServiceRatio());
                user.setFatherBankServiceRatio(partnerCode.getFatherBankServiceRatio());
                break;
            }
        }
        userManager.updateByPrimaryKeyWithVersion(user);
    }

    @Override
    public User updateServicePrice(UpdateUserServicePriceModel model) {
        //验证参数
        userValidator.validateUpdateServicePrice(model);

        User user = userManager.getById(model.getId());

        user.setCommissionMode(model.getCommissionMode());
        user.setMode(model.getMode());
        user.setServiceRatio(model.getServiceRatio());
        user.setBankServiceRatio(model.getBankServiceRatio());
        user.setBenefitRatio(model.getBenefitRatio());
        user.setCostServiceRatio(model.getCostServiceRatio());
        user.setBankCostServiceRatio(model.getBankCostServiceRatio());
        user.setFatherBenefitRatio(model.getFatherBenefitRatio());
        user.setFatherCommissionMode(model.getFatherCommissionMode());
        user.setFatherServiceRatio(model.getFatherServiceRatio());
        user.setFatherBankServiceRatio(model.getFatherBankServiceRatio());

        userManager.updateByPrimaryKeyWithVersion(user);
        return user;
    }

    private UserShard registerUserShard(User user) {
        UserShard userShard = new UserShard();
        userShard.setId(user.getId());
        userShard.setShardId(shardHelper.getShardId(user));
        userShard.setMobile(user.getMobile());
        userShardManager.save(userShard);

        return userShard;
    }

    private User createUser(RegisterModel registerModel) {
        User user = new User();
        user.setMobile(registerModel.getMobile());
        user.setAppVersion(registerModel.getAppVersion() == null ? AppVersion.NORMAL : registerModel.getAppVersion());
        user.setOuterId(registerModel.getOuterId());
        user.setChannelMasterUserId(registerModel.getChannelMasterUserId());
        user.setName(registerModel.getName());
        user.setRemark(registerModel.getRemark());
        user.setVolumeDesc(registerModel.getVolumeDesc());
        user.setMode(ServicePayMode.FIXED_RATIO);
        user.setCommissionMode(CommissionMode.COST_MODE);
        user.setServiceUnitPrice(CoreConstant.DEFAULT_PLATFORM_SERVICE_UNIT_PRICE);
        user.setBankServiceUnitPrice(CoreConstant.DEFAULT_PLATFORM_SERVICE_UNIT_PRICE);
        user.setServiceRatio(CoreConstant.DEFAULT_PLATFORM_SERVICE_UNIT_RATIO);
        user.setBankServiceRatio(CoreConstant.DEFAULT_PLATFORM_SERVICE_UNIT_RATIO);
        user.setServiceRealPrice(user.getServiceUnitPrice());
        user.setTaokeUnitPrice(CoreConstant.DEFAULT_TAOKE_ORDER_UNIT_PRICE);
        user.setRegisterTime(LocalDateTime.now());
        user.setRegisterIp(registerModel.getIp());
        user.setLastLoginTime(LocalDateTime.now());
        user.setLastLoginClient(registerModel.getClientFrom());
        user.setLastLoginIp(registerModel.getIp());
        user.setLoginCount(0L);
        user.setSecurityStatus(SecurityStatus.NORMAL);
        user.setErrorCount(0);
        user.setPartnerBenefit(0L);
        user.setFatherPartnerBenefit(0L);
        user.setBenefitRatio(new BigDecimal("0"));
        user.setFatherBenefitRatio(new BigDecimal("0"));
        user.setUserTag(registerModel.getUserTag());
        user.setIndustryCategory(registerModel.getIndustryCategory());

        if (UserTag.GAME_PLATFORM.equals(registerModel.getUserTag())) {
            user.setServiceRatio(CoreConstant.DEFAULT_GAME_PLATFORM_SERVICE_UNIT_RATIO);
            user.setBankServiceRatio(CoreConstant.DEFAULT_GAME_PLATFORM_SERVICE_UNIT_RATIO);
        }

        //需要特殊处理的字段
        setUserPassword(user, registerModel.getPassword());

        //是否是合伙人推广的
        if (!Boolean.TRUE.equals(registerModel.getAdminRegister()) && !Boolean.TRUE.equals(registerModel.getOpenRegister())) {
            if (Strings.isNullOrEmpty(registerModel.getPma())) {
                throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "邀请码已失效");
            }
        }

        if (registerModel.getPartnerMobile() != null && !Strings.isNullOrEmpty(registerModel.getPartnerMobile().trim())) {
            Partner partner = partnerManager.findByMobile(registerModel.getPartnerMobile().trim());
            if (partner == null) {
                throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "合伙人不存在");
            }

            List<PartnerCode> partnerCodes = partnerCodeManager.listByPartnerId(partner.getId());
            for (PartnerCode partnerCode : partnerCodes) {
                if (UserTag.PLATFORM == partnerCode.getUserTag()) {
                    registerModel.setPma(partnerCode.getPma());
                    break;
                }
            }
        }

        if (!Strings.isNullOrEmpty(registerModel.getPma())) {
            PartnerCode partnerCode = partnerCodeManager.findByPma(registerModel.getPma());
            if (partnerCode == null) {
                throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "注册链接已失效");
            }
            if (!Boolean.TRUE.equals(registerModel.getAdminRegister()) && partnerCode.getStatus() != null && partnerCode.getStatus() == 0) {
                throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "注册链接已失效");
            }
            log.info("createUser partnerCode={}", SerializationUtil.obj2String(partnerCode));
            user.setPartnerId(partnerCode.getPartnerId());
            user.setFatherPartnerId(partnerCode.getFatherPartnerId());

            user.setMode(partnerCode.getMode());
            user.setCommissionMode(partnerCode.getCommissionMode());
            user.setServiceUnitPrice(partnerCode.getServiceUnitPrice());
            user.setBankServiceUnitPrice(partnerCode.getServiceUnitPrice());
            user.setServiceRealPrice(user.getServiceUnitPrice());
            user.setServiceRatio(partnerCode.getServiceRatio());
            user.setBankServiceRatio(partnerCode.getBankServiceRatio());
            user.setPartnerBenefit(partnerCode.getBenefit());
            user.setFatherPartnerBenefit(partnerCode.getFatherBenefit());
            user.setBenefitRatio(partnerCode.getBenefitRatio());
            user.setFatherBenefitRatio(partnerCode.getFatherBenefitRatio());
            user.setCostServiceRatio(partnerCode.getCostServiceRatio());
            user.setBankCostServiceRatio(partnerCode.getSafePayBankCostServiceRatio());
            user.setFatherCommissionMode(partnerCode.getFatherCommissionMode());
            user.setFatherServiceRatio(partnerCode.getFatherServiceRatio());
            user.setFatherBankServiceRatio(partnerCode.getFatherBankServiceRatio());

            user.setUserTag(partnerCode.getUserTag());
            user.setPma(partnerCode.getPma());
        }

        if (user.getUserTag() == null) {
            user.setUserTag(UserTag.NORMAL);
        }

        return user;
    }

    private void setUserPassword(User user, String password) {
        //使用BCrypt加密不需要保存salt,hash值包含了salt的信息
        String crypt = BCrypt.hashpw(password, BCrypt.gensalt());
        user.setPassword(crypt);
    }

    private void setPayPassword(User user, String password) {
        //使用BCrypt加密不需要保存salt,hash值包含了salt的信息
        String crypt = BCrypt.hashpw(password, BCrypt.gensalt());
        user.setPayPassword(crypt);
    }
}
